home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1998 September / Macformat_MF67_1998-09.iso / Shareware Plus / Development / SpriteWorld 2.1 Extra Demos / Platform Scrolling / Platform Scrolling.c < prev    next >
C/C++ Source or Header  |  1998-05-28  |  27KB  |  937 lines

  1. ///--------------------------------------------------------------------------------------
  2. // Platform Scrolling.c
  3. //
  4. // By Vern Jensen. Created in September, 1997.
  5. ///--------------------------------------------------------------------------------------
  6.  
  7.  
  8. #include <SWFPSReport.h>
  9. #include <SWIncludes.h>
  10. #include <SWGameUtils.h>
  11. #include <SWApplication.h>
  12.  
  13. #include "Platform Scrolling.h"
  14.  
  15.  
  16. #define    kFullScreenWindow            true        // Toggles between 512x384 and 640x480
  17. #define kWorldRectInset                0            // Make the SpriteWorld smaller?
  18. #define    kInterlacedMode                false        // Turns Interlaced mode on/off
  19. #define kSyncToVBL                    false        // Sync SpriteWorld to VBL?
  20. #define kMaxFPS                        30            // Set to 0 for unrestricted speed
  21.  
  22.  
  23. #define kWalkIncrease                1
  24. #define kMaxWalkSpeed                10
  25. #define kMaxFallSpeed                20
  26. #define kJumpSpeed                    26
  27. #define kMaxSpriteJumpDistance        19        // How many frames the sprite can keep going up
  28. #define kGravitySpeed                2
  29.  
  30. #define kMovingFloorSpeed            0        // How often the moving floors change frames
  31. #define kMovingFloorForce            2        // How far they move the sprite when the move
  32. #define kChangingFloorSpeed            5        // Frame rate of the changing floor
  33. #define kChangingFloorWait            120        // How long of a delay between on/off
  34. #define kSpikeSpeed                    2        // How fast the spikes move
  35. #define    kSpikeChangeDelay            150        // How long they wait between moves
  36. #define    kExitSignSpeed                8        // Animation speed of exit sign
  37. #define    kArrowSpeed                    10        // Animation speed of arrow
  38.  
  39. #define    kRunningCorrection            7        // Determines how many pixel a sprite can fall through
  40.                                             // the top of a tile and still be put back on top.
  41.                                             // Useful for running across tiles with holes inbetween.
  42.  
  43. #define kSpriteMoveDistance            80            // How far the sprite can move from
  44.                                                 // the center of the screen, in pixels.
  45.                                                 // Try making this value higher!
  46.                                                 
  47.  
  48. #define kTileWidth                    40
  49. #define kTileHeight                    40
  50.  
  51.  
  52. #define kStartRow                    5            // Starting position of sprite
  53. #define kStartCol                    5            // in tile col and row
  54.  
  55.  
  56. #define    kLeftArrowKey                0x7B
  57. #define    kRightArrowKey                0x7C
  58. #define    kDownArrowKey                0x7D
  59. #define    kUpArrowKey                    0x7E
  60.  
  61. #define    kLeftKeyPad                    0x56
  62. #define    kRightKeyPad                0x58
  63. #define    kDownKeyPad                    0x54
  64. #define    kUpKeyPad                    0x5B
  65.  
  66. #define kEscKey                        0x35
  67.  
  68.  
  69. enum tileIDs
  70. {
  71.     kFirstWallTile = 0,
  72.     kLastWallTile = 9,
  73.     kFirstSpikeTile,
  74.     kLastSpikeTile = kFirstSpikeTile + 15,
  75.     kBackgroundTile,
  76.     kFirstLeftFloorTile,
  77.     kLastLeftFloorTile = kFirstLeftFloorTile + 4,
  78.     kFirstRightFloorTile,
  79.     kLastRightFloorTile = kFirstRightFloorTile + 4,
  80.     kFirstChangingTile,
  81.     kLastChangingTile = kFirstChangingTile + 2,
  82.     kFirstBackgroundTile,
  83.     kLastBackgroundTile = kFirstBackgroundTile + 8,
  84.     kFirstExitTile,
  85.     kLastExitTile = kFirstExitTile + 2,
  86.     kMaxNumTiles
  87. };
  88.  
  89.  
  90.  
  91.  
  92. /***********/
  93. /* Globals */
  94. /***********/
  95.  
  96. SpriteWorldPtr        gSpriteWorldP;
  97. SpriteLayerPtr        gSpriteLayerP;
  98. TileMapStructPtr    gTileMapStructP;
  99. TileMapPtr            gTileMap;
  100. SpritePtr            gSimpleSpriteP;
  101. WindowPtr            gWindowP;
  102. short                gCurrentLevel = 128;
  103. Rect                gScreenMidRect, gSpriteInsetRect;
  104. Boolean                gSpriteCanJump, gSpriteIsJumping, gSpriteJumpStage;
  105. Boolean                gChangingFloorMode = true;
  106. Boolean                gDone = false;
  107. Boolean                gEscapeKey = false;
  108. Boolean                gSpikesAreUp = true;
  109. Boolean                gSpriteHitExit = false, gSpriteWasKilled = false;
  110.  
  111. struct moveKeys
  112. {
  113.     Boolean    up;
  114.     Boolean    right;
  115.     Boolean    down;
  116.     Boolean    left;
  117.     Boolean jump;
  118. } gKeys;
  119.  
  120.  
  121. ///--------------------------------------------------------------------------------------
  122. // Main
  123. ///--------------------------------------------------------------------------------------
  124.  
  125. void    main( void )
  126. {
  127.     Initialize(kNumberOfMoreMastersCalls);
  128.     
  129.     if (SWHasSystem7())
  130.     {
  131.         AllowKeyUpEvents();    // Part of SWGameUtils.c
  132.         SetCursor(*GetCursor(watchCursor));
  133.         
  134.         CreateWindow();
  135.         CreateSpriteWorld();
  136.         CreateBallSprite();
  137.         SWLockSpriteWorld(gSpriteWorldP);
  138.         
  139.         SetCursor(&qd.arrow);
  140.         HideCursor();
  141.         
  142.         SetUpAnimation();
  143.         RunAnimation();
  144.         ShutDown();
  145.         
  146.         RestoreEventMask();    // Call this after AllowKeyUpEvents
  147.     }
  148.     else
  149.     {
  150.         CantRunOnThisMachine();
  151.     }
  152. }
  153.  
  154.  
  155. ///--------------------------------------------------------------------------------------
  156. // CreateWindow
  157. ///--------------------------------------------------------------------------------------
  158.  
  159. void     CreateWindow( void )
  160. {
  161.     Rect        windRect;
  162.     RgnHandle    mBarUpdateRgn;
  163.     
  164.     gWindowP = GetNewCWindow(128, NULL, (WindowPtr)-1L);
  165.     
  166.     if (gWindowP == NULL)
  167.     {
  168.         CantFindResource();
  169.     }
  170.     else
  171.     {
  172.         if (kFullScreenWindow)
  173.         {
  174.             SizeWindow(gWindowP, SW_MIN(640, qd.screenBits.bounds.right), 
  175.                 SW_MIN(480, qd.screenBits.bounds.bottom), false);
  176.         }
  177.         else
  178.         {
  179.             SizeWindow(gWindowP, 512, 384, false);
  180.         }
  181.                 
  182.             // Center window in screen
  183.         windRect = gWindowP->portRect;
  184.         CenterRect(&windRect, &qd.screenBits.bounds);
  185.         
  186.             // Make sure window is aligned to long-word boundaries (for 8-bit mode)
  187.         windRect.left = windRect.left>>2<<2;
  188.         
  189.         MoveWindow(gWindowP, windRect.left, windRect.top, false);
  190.         ShowWindow(gWindowP);
  191.         SetPort(gWindowP);
  192.     }
  193.     
  194.     mBarUpdateRgn = HideMenuBar(gWindowP);
  195.     EraseRgn(mBarUpdateRgn);
  196.     DisposeRgn(mBarUpdateRgn);
  197. }
  198.  
  199.  
  200. ///--------------------------------------------------------------------------------------
  201. // CreateSpriteWorld
  202. ///--------------------------------------------------------------------------------------
  203.  
  204. void    CreateSpriteWorld( void )
  205. {
  206.     Rect        offscreenRect, worldRect;
  207.     OSErr        err;
  208.     
  209.     
  210.     err = SWEnterSpriteWorld();
  211.     FatalError(err);
  212.     
  213.     
  214.     worldRect = gWindowP->portRect;
  215.     InsetRect(&worldRect, kWorldRectInset, kWorldRectInset);
  216.     
  217.     
  218.         // Set size of offscreen area
  219.     offscreenRect = worldRect;
  220.     OffsetRect(&offscreenRect, -offscreenRect.left, -offscreenRect.top);
  221.     
  222.  
  223.         // Make offscreen area evenly divisible by tile width & height
  224.     if ( (offscreenRect.right/kTileWidth)*kTileWidth != offscreenRect.right)
  225.         offscreenRect.right = (offscreenRect.right/kTileWidth)*kTileWidth + kTileWidth;
  226.     
  227.     if ( (offscreenRect.bottom/kTileHeight)*kTileHeight != offscreenRect.bottom)
  228.         offscreenRect.bottom = (offscreenRect.bottom/kTileHeight)*kTileHeight + kTileHeight;
  229.     
  230.         // Create the scrolling sprite world
  231.     err = SWCreateSpriteWorldFromWindow(&gSpriteWorldP, (CWindowPtr)gWindowP, 
  232.             &worldRect, &offscreenRect, 0);
  233.     FatalError(err);
  234.     
  235.             // Create the sprite layer
  236.     err = SWCreateSpriteLayer(&gSpriteLayerP);
  237.     FatalError(err);
  238.     
  239.         // Add it to the world
  240.     SWAddSpriteLayer(gSpriteWorldP, gSpriteLayerP);
  241.     
  242.  
  243.     err = SWInitTiling(gSpriteWorldP, kTileHeight, kTileWidth, kMaxNumTiles);
  244.     FatalError(err);
  245.     
  246.     err = SWLoadTileMap(&gTileMapStructP, gCurrentLevel);
  247.     FatalError(err);
  248.  
  249.     SWInstallTileMap(gSpriteWorldP, gTileMapStructP);
  250.     gTileMap = gTileMapStructP->tileMap;
  251.  
  252.         // Load first set of tiles
  253.     err = SWLoadTilesFromPictResource(
  254.         gSpriteWorldP, 
  255.         0,                        // startTileID 
  256.         kMaxNumTiles-1,            // endTileID
  257.         200,                    // pictResID
  258.         0,                        // maskResID
  259.         kNoMask,                // maskType
  260.         0,                        // horizBorderWidth
  261.         0);                        // vertBorderHeight
  262.     FatalError(err);
  263. }
  264.     
  265.  
  266. ///--------------------------------------------------------------------------------------
  267. // CreateBallSprite
  268. ///--------------------------------------------------------------------------------------
  269.  
  270. void    CreateBallSprite( void )
  271. {
  272.     OSErr    err;
  273.     
  274.         // Create the ball sprite    
  275.     err = SWCreateSpriteFromSinglePict(gSpriteWorldP, &gSimpleSpriteP, NULL,
  276.             128, 128, 40, 0, kFatMask);
  277.     FatalError(err);
  278.     
  279.         // Set up the ball sprite
  280.     SWLockSprite(gSimpleSpriteP);
  281.     SWAddSprite(gSpriteLayerP, gSimpleSpriteP);
  282.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  283.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  284.     
  285.         // Inset for left, top, right, and bottom of sprite when checking sprite with tiles
  286.     SetRect(&gSpriteInsetRect, 5, 4, 5, 0);
  287.     gSpriteCanJump = true;
  288.     gSpriteIsJumping = false;
  289.     gSpriteJumpStage = 0;
  290.     
  291.     
  292.         // Set the sprite's drawProc
  293.     if (gSpriteWorldP->pixelDepth == 8)        // If in 256 colors
  294.     {
  295.         if (kInterlacedMode)
  296.             SWSetSpriteDrawProc(gSimpleSpriteP, BP8BitInterlacedMaskDrawProc);
  297.         else
  298.             SWSetSpriteDrawProc(gSimpleSpriteP, BlitPixie8BitMaskDrawProc);
  299.     }
  300.     else if ( !(SW_PPC && gSpriteWorldP->pixelDepth < 8) )        // Not 256 colors
  301.     {
  302.             // Use interlaced drawProcs unless in B&W, where interlacing is ugly
  303.         if (kInterlacedMode && gSpriteWorldP->pixelDepth > 2)
  304.             SWSetSpriteDrawProc(gSimpleSpriteP, BPAllBitInterlacedMaskDrawProc);
  305.         else
  306.             SWSetSpriteDrawProc(gSimpleSpriteP, BlitPixieAllBitMaskDrawProc);
  307.     }
  308. }
  309.  
  310.  
  311. ///--------------------------------------------------------------------------------------
  312. // SetUpAnimation
  313. ///--------------------------------------------------------------------------------------
  314.  
  315. void    SetUpAnimation( void )
  316. {
  317.     Rect        moveBoundsRect;
  318.     
  319.     SWSetSpriteLocation(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  320.     ResetKeys();
  321.     
  322.         // Set up data used by the SmoothScrollingWorldMoveProc
  323.     gScreenMidRect = gSimpleSpriteP->curFrameP->frameRect;
  324.     CenterRect( &gScreenMidRect, &gSpriteWorldP->backRect );
  325.     
  326.     SWSetSpriteWorldMaxFPS(gSpriteWorldP, kMaxFPS);
  327.     SWSyncSpriteWorldToVBL(gSpriteWorldP, kSyncToVBL);
  328.     
  329.         // movement boundary = size of tileMap
  330.     SetRect(&moveBoundsRect, 0, 0, 
  331.             gTileMapStructP->numCols * kTileWidth, 
  332.             gTileMapStructP->numRows * kTileHeight);
  333.     
  334.     SWSetTileChangeProc(gSpriteWorldP, TileChangeProc);
  335.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  336.     SWSetScrollingWorldMoveProc(gSpriteWorldP, SmoothScrollingWorldMoveProc, gSimpleSpriteP);
  337.         
  338.         // Move visScrollRect to starting sprite position
  339.     SWMoveVisScrollRect(gSpriteWorldP, 
  340.         gSpriteWorldP->followSpriteP->destFrameRect.left - gSpriteWorldP->backRect.right/2,
  341.         gSpriteWorldP->followSpriteP->destFrameRect.top - gSpriteWorldP->backRect.bottom/2);
  342.  
  343.     if (gSpriteWorldP->pixelDepth == 8)        // If in 256 colors
  344.     {
  345.         if (kInterlacedMode)
  346.         {
  347.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BP8BitInterlacedRectDrawProc);
  348.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BP8BitInterlacedRectDrawProc);
  349.             SWSetTileMaskDrawProc(gSpriteWorldP, BP8BitInterlacedPartialMaskDrawProc);
  350.             SWSetDoubleRectDrawProc(gSpriteWorldP, BP8BitInterlacedDoubleRectDrawProc);
  351.         }
  352.         else
  353.         {
  354.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixie8BitRectDrawProc);
  355.             SWSetTileMaskDrawProc(gSpriteWorldP, BlitPixie8BitPartialMaskDrawProc);
  356.             SWSetDoubleRectDrawProc(gSpriteWorldP, BlitPixie8BitDoubleRectDrawProc);
  357.         }
  358.     }    // When running on PPC, we can't use the AllBit blitters in lower than 8-bit
  359.     else if ( !(SW_PPC && gSpriteWorldP->pixelDepth < 8) )    // Not 256 colors
  360.     {
  361.         if (kInterlacedMode && gSpriteWorldP->pixelDepth > 2)
  362.         {
  363.                 // Use interlaced drawProcs unless in B&W, where interlacing is ugly
  364.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BPAllBitInterlacedRectDrawProc);
  365.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BPAllBitInterlacedRectDrawProc);
  366.             SWSetTileMaskDrawProc(gSpriteWorldP, BPAllBitInterlacedPartialMaskDrawProc);
  367.             if (gSpriteWorldP->pixelDepth == 16)
  368.                 SWSetDoubleRectDrawProc(gSpriteWorldP, BP16BitInterlacedDoubleRectDrawProc);
  369.         }
  370.         else
  371.         {
  372.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  373.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  374.             SWSetTileMaskDrawProc(gSpriteWorldP, BlitPixieAllBitPartialMaskDrawProc);
  375.             if (gSpriteWorldP->pixelDepth == 16)
  376.                 SWSetDoubleRectDrawProc(gSpriteWorldP, BlitPixie16BitDoubleRectDrawProc);
  377.         }
  378.     }
  379.     
  380.     
  381.         // Make sure CopyBits, if used, doesn't try to colorize things
  382.     SWSetPortToWindow(gSpriteWorldP);
  383.     ForeColor(blackColor);
  384.     BackColor(whiteColor);
  385.     
  386.     SWDrawTilesInBackground(gSpriteWorldP);
  387.     SWUpdateScrollingSpriteWorld(gSpriteWorldP, true);
  388. }
  389.  
  390.  
  391. ///--------------------------------------------------------------------------------------
  392. //  RunAnimation
  393. ///--------------------------------------------------------------------------------------
  394.  
  395. void    RunAnimation( void )
  396. {
  397.     unsigned long        frames;
  398.     
  399.     frames = 0;
  400.     StartTimer();
  401.     
  402.     gEscapeKey = false;
  403.  
  404.     while (!Button() && !gEscapeKey)
  405.     {
  406.         SWProcessScrollingSpriteWorld(gSpriteWorldP);
  407.         SWAnimateScrollingSpriteWorld(gSpriteWorldP);
  408.         
  409.             // We call this in case the Control Strip or something changes our window's visRgn
  410.         KeepMenuBarHidden(gWindowP);
  411.         
  412.         if (gSpriteWorldP->frameHasOccurred)
  413.         {
  414.             frames++;
  415.             
  416.             if (gSpriteHitExit)
  417.                 AdvanceLevel();
  418.             else if (gSpriteWasKilled)
  419.                 KillSprite();
  420.         }
  421.     }
  422.     
  423.     
  424.     ShowMenuBar(gWindowP);
  425.     ShowResults(frames);
  426. }
  427.  
  428.  
  429. ///--------------------------------------------------------------------------------------
  430. //  ShutDown (clean up and dispose of the SpriteWorld)
  431. ///--------------------------------------------------------------------------------------
  432.  
  433. void    ShutDown( void )
  434. {
  435.     SWDisposeSpriteWorld(gSpriteWorldP);
  436.     SWExitSpriteWorld();
  437.     
  438.     FlushEvents(everyEvent, 0);
  439.     ShowCursor();
  440. }
  441.  
  442.  
  443. ///--------------------------------------------------------------------------------------
  444. //  KeySpriteMoveProc
  445. ///--------------------------------------------------------------------------------------
  446.  
  447. SW_FUNC void KeySpriteMoveProc(SpritePtr srcSpriteP)
  448. {
  449.     short        horizDir, tempHorizDelta;
  450.     Boolean        spriteIsOnGround = false;
  451.     
  452.     UpdateKeys();    // Put the latest key values in the keys structure
  453.     
  454.     
  455.         // See if the sprite is standing on a wall
  456.     spriteIsOnGround = false;
  457.     if ( ((srcSpriteP->destFrameRect.bottom - gSpriteInsetRect.bottom) / kTileHeight) *
  458.         kTileHeight == srcSpriteP->destFrameRect.bottom - gSpriteInsetRect.bottom )
  459.     {
  460.         gSpriteInsetRect.bottom--;    // Check one line lower than bottom of sprite
  461.         
  462.         if (SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  463.                 &gSpriteInsetRect, kFirstWallTile, kLastWallTile, false) ||
  464.             SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  465.                  &gSpriteInsetRect, kFirstLeftFloorTile, kLastChangingTile, false) )
  466.         {
  467.             spriteIsOnGround = true;
  468.         }
  469.         
  470.         gSpriteInsetRect.bottom++;    // Change rect to the way it was before
  471.     }
  472.     
  473.     
  474.     horizDir = (gKeys.right - gKeys.left);
  475.     
  476.     if (horizDir)        // Are we moving left or right?
  477.     {
  478.             // Did we change direction?
  479.         if ( (srcSpriteP->horizMoveDelta > 0 && horizDir < 0) ||
  480.              (srcSpriteP->horizMoveDelta < 0 && horizDir > 0) )
  481.         {
  482.             srcSpriteP->horizMoveDelta = 0;
  483.         }
  484.         
  485.             // Add speed to sprite
  486.         srcSpriteP->horizMoveDelta += horizDir * kWalkIncrease;
  487.         
  488.             // Keep from moving too fast
  489.         if (srcSpriteP->horizMoveDelta > kMaxWalkSpeed)
  490.             srcSpriteP->horizMoveDelta = kMaxWalkSpeed;
  491.         else if (srcSpriteP->horizMoveDelta < -kMaxWalkSpeed)
  492.             srcSpriteP->horizMoveDelta = -kMaxWalkSpeed;
  493.     }
  494.     else    // We're not moving, so slow down
  495.     {
  496.         if (srcSpriteP->horizMoveDelta > 0)
  497.             srcSpriteP->horizMoveDelta /= 2;
  498.         else if (srcSpriteP->horizMoveDelta < 0)
  499.             srcSpriteP->horizMoveDelta /= 2;
  500.     }    
  501.     
  502.         
  503.     if (gKeys.up && gSpriteIsJumping)    // Already jumping - continue going up
  504.     {
  505.         if (gSpriteJumpStage++ < kMaxSpriteJumpDistance)
  506.         {
  507.             srcSpriteP->vertMoveDelta = -kJumpSpeed + gSpriteJumpStage * 1.4;
  508.         }
  509.         else
  510.         {
  511.             gSpriteIsJumping = false;
  512.         }
  513.     }
  514.     else if (gKeys.up && gSpriteCanJump)    // Start new jump
  515.     {
  516.         if (spriteIsOnGround)
  517.         {
  518.             srcSpriteP->vertMoveDelta = -kJumpSpeed;
  519.             gSpriteIsJumping = true;
  520.             gSpriteCanJump = false;
  521.             gSpriteJumpStage = 0;
  522.         }
  523.     }
  524.     else    // Stopped jumping, so make it fall early
  525.     {
  526.         if (srcSpriteP->vertMoveDelta < 0)
  527.             srcSpriteP->vertMoveDelta += 3;
  528.         
  529.         gSpriteIsJumping = false;
  530.         
  531.         if (!gKeys.up && srcSpriteP->vertMoveDelta >= 0)
  532.             gSpriteCanJump = true;
  533.     }
  534.     
  535.         // Add gravity
  536.     srcSpriteP->vertMoveDelta += kGravitySpeed;
  537.         
  538.         // Keep ball from falling too fast
  539.     if (srcSpriteP->vertMoveDelta > kMaxFallSpeed)
  540.         srcSpriteP->vertMoveDelta = kMaxFallSpeed;
  541.  
  542.  
  543.  
  544.     srcSpriteP->destFrameRect.top += srcSpriteP->vertMoveDelta;
  545.     srcSpriteP->destFrameRect.bottom += srcSpriteP->vertMoveDelta;
  546.     tempHorizDelta = 0;
  547.     
  548.  
  549.         // Check for collisions with walls vertically
  550.     if (srcSpriteP->vertMoveDelta > 0)            // Moving down
  551.     {
  552.             // Make sure sprite was above the tile before we fell through it. Otherwise,
  553.             // the sprite was never on top, and shouldn't be moved by the platform.
  554.         if ( ((srcSpriteP->oldFrameRect.bottom-1) / kTileHeight) < 
  555.              ((srcSpriteP->destFrameRect.bottom-1) / kTileHeight) )
  556.         {
  557.                 // Check for floors moving left
  558.             if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  559.                 &gSpriteInsetRect, kFirstLeftFloorTile, kFirstLeftFloorTile, false) )
  560.             {
  561.                 tempHorizDelta -= kMovingFloorForce;
  562.             }
  563.             
  564.                 // Check for floors moving right
  565.             if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  566.                  &gSpriteInsetRect, kFirstRightFloorTile, kFirstRightFloorTile, false) )
  567.             {
  568.                 tempHorizDelta += kMovingFloorForce;
  569.             }
  570.         }
  571.         
  572.             // Make sure sprite was above the tile before we fell through it. If so, we 
  573.             // move the sprite back on top of the tile, otherwise we never were on top.
  574.         if ( ((srcSpriteP->oldFrameRect.bottom-1 - kRunningCorrection) / kTileHeight) < 
  575.              ((srcSpriteP->destFrameRect.bottom-1) / kTileHeight) )
  576.         {
  577.                 // Keep sprite from falling through moving floors
  578.             if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  579.                  &gSpriteInsetRect, kFirstLeftFloorTile, kFirstRightFloorTile, true) )
  580.             {
  581.                 srcSpriteP->vertMoveDelta = 0;
  582.             }
  583.                 // Keep sprite from falling through a changing floor
  584.             else if ( gChangingFloorMode == true &&
  585.                 SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  586.                 &gSpriteInsetRect, kFirstChangingTile, kFirstChangingTile, true) )
  587.             {
  588.                 srcSpriteP->vertMoveDelta = 0;
  589.             }
  590.         }
  591.         
  592.             // Make sure sprite doesn't fall through any walls
  593.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  594.             &gSpriteInsetRect, kFirstWallTile, kLastWallTile, true) )
  595.         {
  596.             srcSpriteP->vertMoveDelta = 0;
  597.         }
  598.     }
  599.     else if (srcSpriteP->vertMoveDelta < 0)        // Moving up
  600.     {
  601.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWTopSide,
  602.             &gSpriteInsetRect, kFirstWallTile, kLastWallTile, true) )
  603.         {
  604.             srcSpriteP->vertMoveDelta /= 2;
  605.             gSpriteIsJumping = false;
  606.         }
  607.     }
  608.     
  609.     
  610.     srcSpriteP->destFrameRect.right += srcSpriteP->horizMoveDelta + tempHorizDelta;
  611.     srcSpriteP->destFrameRect.left += srcSpriteP->horizMoveDelta + tempHorizDelta;
  612.     gSpriteInsetRect.bottom += kRunningCorrection;
  613.     
  614.             // Check for collisions with walls horizontally
  615.     if (srcSpriteP->horizMoveDelta + tempHorizDelta > 0)        // Moving right
  616.     {
  617.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWRightSide,
  618.             &gSpriteInsetRect, kFirstWallTile, kLastWallTile, true) )
  619.         {
  620.             if (srcSpriteP->horizMoveDelta > 0)
  621.                 srcSpriteP->horizMoveDelta = 1;
  622.         }
  623.     }
  624.     else if (srcSpriteP->horizMoveDelta + tempHorizDelta < 0)    // Moving left
  625.     {
  626.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWLeftSide,
  627.             &gSpriteInsetRect, kFirstWallTile, kLastWallTile, true) )
  628.         {
  629.             if (srcSpriteP->horizMoveDelta < 0)
  630.                 srcSpriteP->horizMoveDelta = -1;
  631.         }
  632.     }
  633.     
  634.     gSpriteInsetRect.bottom -= kRunningCorrection;
  635.     srcSpriteP->needsToBeDrawn = true;
  636.     
  637.     
  638.         // See if sprite hit exit sign or spikes
  639.     if (SWCheckSpriteWithTiles(gSpriteWorldP, gSimpleSpriteP, kSWEntireSprite,
  640.          &gSpriteInsetRect, kFirstExitTile, kLastExitTile, false) )
  641.     {
  642.         gSpriteHitExit = true;
  643.     }
  644.     else if (gSpikesAreUp && SWCheckSpriteWithTiles(gSpriteWorldP, gSimpleSpriteP,
  645.              kSWEntireSprite, &gSpriteInsetRect, kFirstSpikeTile, kLastSpikeTile, false) )
  646.     {
  647.         gSpriteWasKilled = true;
  648.     }
  649. }
  650.  
  651.  
  652. ///--------------------------------------------------------------------------------------
  653. //  TileChangeProc
  654. ///--------------------------------------------------------------------------------------
  655.  
  656. SW_FUNC void TileChangeProc(SpriteWorldPtr spriteWorldP)
  657. {
  658.     short            curImage;
  659.     static short    wallDelay = 0, spikeTimer = 0, spikeDirection = 0, spikeDelay = 0;
  660.     static short    changingFloorDelay = 0, changingFloorWait = 0, exitDelay = 0;
  661.     static Boolean    spikesAreMoving = false;
  662.     static short    oldTicks = 0;
  663.     short            ticksPassed, ticks;
  664.     
  665.         // Initialize oldTicks the first time this function is called
  666.     if (oldTicks == 0)
  667.         oldTicks = TickCount();
  668.     
  669.     ticks = TickCount();
  670.     ticksPassed = ticks - oldTicks;        // Number of ticks passed since last call
  671.     oldTicks = ticks;
  672.     
  673.     changingFloorWait += ticksPassed;
  674.     if (changingFloorWait >= kChangingFloorWait)
  675.     {
  676.         changingFloorWait = 0;
  677.         if (gChangingFloorMode == true)
  678.         {
  679.             gChangingFloorMode = 0;
  680.             SWChangeTileImage(spriteWorldP, kFirstChangingTile, kBackgroundTile);
  681.         }
  682.         else
  683.         {
  684.             gChangingFloorMode = 1;
  685.             SWChangeTileImage(spriteWorldP, kFirstChangingTile, kFirstChangingTile);
  686.         }
  687.     }
  688.     
  689.         // Change the changing floor
  690.     if (gChangingFloorMode == true)
  691.     {
  692.         changingFloorDelay += ticksPassed;
  693.         if (changingFloorDelay >= kChangingFloorSpeed)
  694.         {
  695.             curImage = spriteWorldP->curTileImage[kFirstChangingTile];
  696.             if (curImage < kLastChangingTile)
  697.                 curImage++;
  698.             else
  699.                 curImage = kFirstChangingTile;
  700.             
  701.             SWChangeTileImage(spriteWorldP, kFirstChangingTile, curImage);
  702.             changingFloorDelay = 0;
  703.         }
  704.     }
  705.     
  706.         // Change the moving floors
  707.     wallDelay += ticksPassed;
  708.     if (wallDelay >= kMovingFloorSpeed)
  709.     {
  710.             // Move the left wall
  711.         curImage = spriteWorldP->curTileImage[kFirstLeftFloorTile];
  712.         if (curImage < kLastLeftFloorTile)
  713.             curImage++;
  714.         else
  715.             curImage = kFirstLeftFloorTile;
  716.         
  717.         SWChangeTileImage(spriteWorldP, kFirstLeftFloorTile, curImage);
  718.         
  719.             // Move the right wall
  720.         curImage = spriteWorldP->curTileImage[kFirstRightFloorTile];
  721.         if (curImage < kLastRightFloorTile)
  722.             curImage++;
  723.         else
  724.             curImage = kFirstRightFloorTile;
  725.         
  726.         SWChangeTileImage(spriteWorldP, kFirstRightFloorTile, curImage);
  727.         
  728.         wallDelay = 0;
  729.     }
  730.     
  731.     
  732.         // Change the spikes
  733.     if (spikesAreMoving)
  734.     {
  735.         spikeDelay += ticksPassed;
  736.         if (spikeDelay >= kSpikeSpeed)
  737.         {
  738.             curImage = spriteWorldP->curTileImage[kFirstSpikeTile];
  739.             curImage += spikeDirection;
  740.             if (curImage == kLastSpikeTile+1 || curImage == kFirstSpikeTile)
  741.             {        
  742.                 spikesAreMoving = false;
  743.                 if (spikeDirection > 0)
  744.                     spikeDirection = -1;
  745.                 else
  746.                     spikeDirection = 1;
  747.             }
  748.             
  749.                 // Determine whether the current spike position can kill the sprite
  750.             if (curImage > kFirstSpikeTile + 7)
  751.                 gSpikesAreUp = false;
  752.             else
  753.                 gSpikesAreUp = true;
  754.             
  755.             SWChangeTileImage(spriteWorldP, kFirstSpikeTile, curImage);
  756.             spikeDelay = 0;
  757.         }
  758.     }
  759.     else
  760.     {
  761.         spikeTimer += ticksPassed;
  762.         if (spikeTimer > kSpikeChangeDelay)
  763.         {
  764.             spikeTimer = 0;
  765.             spikesAreMoving = true;
  766.         }
  767.     }
  768.     
  769.  
  770.         // Animate the exit sign
  771.     exitDelay += ticksPassed;
  772.     if (exitDelay >= kExitSignSpeed)
  773.     {
  774.         curImage = spriteWorldP->curTileImage[kFirstExitTile];
  775.         if (curImage < kLastExitTile)
  776.             curImage++;
  777.         else
  778.             curImage = kFirstExitTile;
  779.         
  780.         SWChangeTileImage(spriteWorldP, kFirstExitTile, curImage);
  781.         exitDelay = 0;
  782.     }
  783. }
  784.  
  785.  
  786. ///--------------------------------------------------------------------------------------
  787. //  SmoothScrollingWorldMoveProc - our scrolling WorldMoveProc
  788. ///--------------------------------------------------------------------------------------
  789.  
  790. SW_FUNC void SmoothScrollingWorldMoveProc(
  791.     SpriteWorldPtr spriteWorldP,
  792.     SpritePtr followSpriteP)
  793. {    
  794.     short    screenMidRectTop, screenMidRectLeft;
  795.     
  796.     screenMidRectTop = gScreenMidRect.top + spriteWorldP->visScrollRect.top;
  797.     screenMidRectLeft = gScreenMidRect.left + spriteWorldP->visScrollRect.left;
  798.     
  799.     
  800.     spriteWorldP->horizScrollDelta = (kMaxWalkSpeed * 
  801.         (followSpriteP->destFrameRect.left - screenMidRectLeft) ) / kSpriteMoveDistance;
  802.     
  803.     spriteWorldP->vertScrollDelta = (kMaxFallSpeed * 
  804.         (followSpriteP->destFrameRect.top - screenMidRectTop) ) / kSpriteMoveDistance;
  805.     
  806.     if (kInterlacedMode)
  807.         spriteWorldP->vertScrollDelta = spriteWorldP->vertScrollDelta>>1<<1;
  808. }
  809.  
  810.  
  811. ///--------------------------------------------------------------------------------------
  812. //  UpdateKeys (Put the latest key values in the keys structure)
  813. ///--------------------------------------------------------------------------------------
  814.  
  815. void    UpdateKeys( void )
  816. {
  817.     EventRecord        event;
  818.     short            theKey;
  819.     Boolean            isDown;
  820.     
  821.     
  822.     while ( GetOSEvent( (keyUpMask | keyDownMask), &event ) )
  823.     {
  824.         theKey = (event.message & keyCodeMask) >> 8;
  825.         isDown = (event.what != keyUp);
  826.         
  827.         if ( (theKey == kLeftArrowKey) || (theKey == kLeftKeyPad) )
  828.             gKeys.left = isDown;
  829.         else if ( (theKey == kRightArrowKey) || (theKey == kRightKeyPad) )
  830.             gKeys.right = isDown;
  831.         else if ( (theKey == kDownArrowKey) || (theKey == kDownKeyPad) )
  832.             gKeys.down = isDown;
  833.         else if ( (theKey == kUpArrowKey) || (theKey == kUpKeyPad) )
  834.             gKeys.up = isDown;
  835.         else if (theKey == kEscKey)
  836.             gEscapeKey = isDown;
  837.     }
  838. }
  839.  
  840.  
  841. ///--------------------------------------------------------------------------------------
  842. //  ResetKeys (Called when setting up a new game)
  843. ///--------------------------------------------------------------------------------------
  844.  
  845. void    ResetKeys( void )
  846. {
  847.     gKeys.left = 0;
  848.     gKeys.right = 0;
  849.     gKeys.down = 0;
  850.     gKeys.up = 0;
  851.     gEscapeKey = 0;
  852. }
  853.  
  854.  
  855. ///--------------------------------------------------------------------------------------
  856. //  AdvanceLevel
  857. ///--------------------------------------------------------------------------------------
  858.  
  859. void    AdvanceLevel( void )
  860. {
  861.     Rect            moveBoundsRect;
  862.     unsigned long    junkTime;
  863.     OSErr            err;
  864.     
  865.     gCurrentLevel++;
  866.     gSpriteHitExit = false;
  867.     
  868.     SWDisposeTileMap(&gTileMapStructP);
  869.     err = SWLoadTileMap(&gTileMapStructP, gCurrentLevel);
  870.     if (err)
  871.     {
  872.         gCurrentLevel = 128;
  873.         err = SWLoadTileMap(&gTileMapStructP, gCurrentLevel);
  874.         FatalError(err);
  875.     }
  876.     
  877.     gTileMap = gTileMapStructP->tileMap;
  878.     SWInstallTileMap(gSpriteWorldP, gTileMapStructP);
  879.     
  880.         // Reset scrolling moveBounds for new TileMap
  881.     SetRect(&moveBoundsRect, 0, 0, 
  882.         gTileMapStructP->numCols * kTileWidth, 
  883.         gTileMapStructP->numRows * kTileHeight);
  884.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  885.     
  886.     
  887.     ResetSprite();
  888.     Delay(30, &junkTime);
  889.     
  890.     SWDrawTilesInBackground(gSpriteWorldP);
  891.     SWUpdateSpriteWorld(gSpriteWorldP, false);
  892. }
  893.  
  894.  
  895. ///--------------------------------------------------------------------------------------
  896. //  KillSprite
  897. ///--------------------------------------------------------------------------------------
  898.  
  899. void    KillSprite( void )
  900. {
  901.     unsigned long    dummyTicks;
  902.     
  903.     gSpriteWasKilled = false;
  904.     SWSetSpriteFrameTime(gSimpleSpriteP, 1000/15);
  905.     SWSetSpriteFrameAdvance(gSimpleSpriteP, 1);
  906.     SWSetSpriteMoveProc(gSimpleSpriteP, NULL);
  907.     
  908.     do
  909.     {        // Run the "popped ball" animation
  910.         SWProcessScrollingSpriteWorld(gSpriteWorldP);
  911.         SWAnimateScrollingSpriteWorld(gSpriteWorldP);
  912.     } while (gSimpleSpriteP->curFrameIndex < gSimpleSpriteP->maxFrames-1);
  913.     
  914.     Delay(23, &dummyTicks);
  915.     ResetSprite();
  916. }
  917.  
  918.  
  919. ///--------------------------------------------------------------------------------------
  920. //  ResetSprite
  921. ///--------------------------------------------------------------------------------------
  922.  
  923. void    ResetSprite( void )
  924. {
  925.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  926.     SWMoveSprite(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  927.     SWMoveVisScrollRect(gSpriteWorldP, 0, 0);
  928.     
  929.     SWSetSpriteFrameAdvance(gSimpleSpriteP, 0);
  930.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  931.     SWSetCurrentFrameIndex(gSimpleSpriteP, 0);
  932.     
  933.     gSpriteCanJump = false;
  934.     gSpriteIsJumping = false;
  935.     gSpriteJumpStage = 0;
  936. }
  937.